/*
 * Copyright (c) 2009 Johnny Mast
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
#import "SpriteSheet.h"

@interface SpriteSheet (Private)
	-(void)initImp;
	-(void)calculateCachedTextureCoordinates;
	-(UIImage * )getSpriteAtRow:(float)row col:(float)col;
@end


@implementation SpriteSheet
@synthesize SpriteSheetImage;
@synthesize cachedTextureCoordinates;
@synthesize horizontal;
@synthesize vertical;
@synthesize SpriteWidth;
@synthesize SpriteHeight;
@synthesize SpriteScale;
@synthesize SpriteSpacing;
@synthesize image;
@synthesize Resource;


- (void) dealloc
{
	free(cachedTextureCoordinates);
	[image release];
	[Resource release];
	[SpriteSheetImage release];
	[super dealloc];
}

-(id)initWithSpriteSheet:(NSString*)sheetname {
	self = [super init];
	if (self != nil) {
		image = [(Image *)[Image alloc] initWithImage:sheetname filter:GL_NEAREST];
		SpriteSheetImage = [UIImage imageNamed:sheetname];
		[self setWidth:16.0f];
		[self setHeight:16.0f];
		[self setSpacing:0.0f];
		[self setScale:1.0f];
		[self initImp];
	}
	return self;	
}


- (id)initWithImageNamed:(NSString*)sheetname spriteWidth:(GLuint)width spriteHeight:(GLuint)height spacing:(GLuint)imageSpacing imageScale:(GLuint)imageScale {
	self = [super init];
	if (self != nil) {
		image = [(Image *)[Image alloc] initWithImage:sheetname filter:GL_NEAREST];
		SpriteSheetImage = [UIImage imageNamed:sheetname];
		[self setWidth:width];
		[self setHeight:height];
		[self setSpacing:imageSpacing];
		[self setScale:imageScale];
		[self initImp];
	}
	return self;
}


-(void)setHeight:(GLuint)spriteheight {
	SpriteHeight = spriteheight;
	[self initImp];
}

-(void)setWidth:(GLuint)spritewidth {
	SpriteWidth = spritewidth;
	[self initImp];
}

-(void)setSpacing:(GLuint)spritespacing {
	SpriteSpacing = spritespacing;	
	[self initImp];
}


-(void)setScale:(GLuint)spritescale {
	SpriteScale = spritescale;
	[self initImp];
}


- (Quad2f)getTextureCoordsForSpriteAtX:(GLuint)x y:(GLuint)y {
	
    // Calculate the location within the texture coordinates array based on the 
    // x and y location provided
    int index = y * horizontal + x;
    
    // Check to make sure the coordinates are within range else raise an error
    if(index > horizontal*vertical) {
        NSLog(@"ERROR - SpriteSheet: texture location out of range.");
    }    
//    NSLog(@"dit is een test %@", cachedTextureCoordinates);
	if (cachedTextureCoordinates)
		NSLog(@"oooh geen cashed textures");
	
    // Return the coordinates at the specified location
	return cachedTextureCoordinates[index];
}

- (Image*)getSpriteAtX:(GLuint)x y:(GLuint)y {
	
	//Calculate the point from which the sprite should be taken within the spritesheet
	CGPoint spritePoint = [self getOffsetForSpriteAtX:x y:y];
	
	// Return the subimage defined by the point and dimensions of a sprite.  This will use the spritesheet
	// images scale so that it is respected in the image returned
	return [[image getSubImageAtPoint:spritePoint subImageWidth:SpriteWidth subImageHeight:SpriteHeight scale:[image scale]] retain];
}


- (void)renderSpriteAtX:(GLuint)x y:(GLuint)y point:(CGPoint)aPoint centerOfImage:(BOOL)aCenter {
	//Calculate the point from which the sprite should be taken within the spritesheet
	CGPoint spritePoint = [self getOffsetForSpriteAtX:x y:y];
	
	// Rather than return a new image for this sprite we are going to just render the specified
	// sprite at the specified location
	[image renderSubImageAtPoint:aPoint offset:spritePoint subImageWidth:SpriteWidth subImageHeight:SpriteHeight centerOfImage:aCenter];
}

- (Quad2f*)getVerticesForSpriteAtX:(GLuint)x y:(GLuint)y point:(CGPoint)aPoint centerOfImage:(BOOL)aCenter {
	[image calculateVerticesAtPoint:aPoint subImageWidth:SpriteWidth subImageHeight:SpriteHeight centerOfImage:aCenter];
	return [image vertices];
}




- (CGPoint)getOffsetForSpriteAtX:(int)x y:(int)y {
	return CGPointMake(x * (SpriteWidth + SpriteSpacing), y * (SpriteHeight + SpriteSpacing));	
}




-(Image * )getImageAtRow:(float)row col:(float)col
{
	
	Image* subimage        = nil;
	
	UIImage* newImage            = [self getSpriteAtRow:row col:col];
	
	subimage = [[Image alloc] initWithUIImage:newImage scale:1.0f filter:GL_NEAREST] ;
	return subimage;
}


@end


@implementation SpriteSheet (Private)

-(void)initImp {
//	horizontal = (([image imageWidth] - SpriteWidth) / (SpriteWidth + SpriteSpacing)) + 1;
//	vertical =  (([image imageHeight] - SpriteHeight) / (SpriteHeight + SpriteSpacing)) + 1;

//	if(([image imageHeight] - SpriteHeight) % (SpriteHeight + SpriteSpacing) != 0) {
//		vertical++;
//	}
	
	Resource = [[Resources alloc] init];
	
	
	// Allocate the memory needed for the texture coordinates array
    cachedTextureCoordinates = calloc((horizontal*vertical), sizeof(Quad2f));
	[self cachedTextureCoordinates];
}

- (void)calculateCachedTextureCoordinates {
    // Loop through the rows and columns of the spritsheet calculating the texture coordinates
    // These coordinates are stored and returned when required to help performance
    int spriteSheetCount = 0;
    for(int i=0; i<vertical; i++) {
        for(int j=0; j<horizontal; j++) {
            CGPoint spritePoint = [self getOffsetForSpriteAtX:j y:i];
           	[image calculateTexCoordsAtOffset:spritePoint subImageWidth:SpriteWidth subImageHeight:SpriteHeight];
            Quad2f t = *[image textureCoordinates];
            cachedTextureCoordinates[spriteSheetCount] = t;
            spriteSheetCount++;
        }
    }
}

-(void) addRoundedRectToPath:(CGContextRef)context rect:(CGRect) rect ovalWidth:(float)ovalWidth ovalHeight:(float)ovalHeight
{
    float fw, fh;
    if (ovalWidth == 0 || ovalHeight == 0) {
        CGContextAddRect(context, rect);
        return;
    }
    CGContextSaveGState(context);
    CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGContextScaleCTM (context, ovalWidth, ovalHeight);
    fw = CGRectGetWidth (rect) / ovalWidth;
    fh = CGRectGetHeight (rect) / ovalHeight;
    CGContextMoveToPoint(context, fw, fh/2);
    CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
    CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
    CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
    CGContextClosePath(context);
    CGContextRestoreGState(context);
}


- (UIImage*)imageByScalingAndCroppingForSize:(UIImage *)_image targetSize:(CGSize)targetSize
{
	
	
	UIImage *sourceImage = _image;
	UIImage *newImage = nil;        
	CGSize imageSize = sourceImage.size;
	CGFloat srcwidth = imageSize.width;
	CGFloat srcheight = imageSize.height;
	CGFloat targetWidth = targetSize.width;
	CGFloat targetHeight = targetSize.height;
	CGFloat scaleFactor = 0.0;
	CGFloat scaledWidth = targetWidth;
	CGFloat scaledHeight = targetHeight;
	CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
	
	if (CGSizeEqualToSize(imageSize, targetSize) == NO) 
	{
        CGFloat widthFactor = targetWidth / srcwidth;
        CGFloat heightFactor = targetHeight / srcheight;
		
        if (widthFactor > heightFactor) 
			scaleFactor = widthFactor; // scale to fit height
        else
			scaleFactor = heightFactor; // scale to fit width
        scaledWidth  = srcwidth * scaleFactor;
        scaledHeight = srcheight * scaleFactor;
		
        // center the image
        if (widthFactor > heightFactor)
		{
			thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
		}
        else 
			if (widthFactor < heightFactor)
			{
				thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
			}
	}       
	
	UIGraphicsBeginImageContext(targetSize); // this will crop
	
	CGRect thumbnailRect = CGRectZero;
	thumbnailRect.origin = thumbnailPoint;
	thumbnailRect.size.width  = scaledWidth;
	thumbnailRect.size.height = scaledHeight;
	
	[sourceImage drawInRect:thumbnailRect];
	
	newImage = UIGraphicsGetImageFromCurrentImageContext();
	if(newImage == nil) 
        NSLog(@"could not scale image");
	
	//pop the context to get back to the default
	UIGraphicsEndImageContext();
	return newImage;
}


-(UIImage * )getSprite:(float)x y:(float)y {
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, SpriteWidth, SpriteHeight, 8,4 * SpriteWidth, colorSpace, kCGImageAlphaPremultipliedFirst);
    CGColorSpaceRelease(colorSpace);
    
	
	CGImageRef copy = CGImageCreateWithImageInRect(SpriteSheetImage.CGImage, CGRectMake(x, y, SpriteWidth, SpriteHeight));
	
	
	if (copy) {
        CGContextDrawImage(context, CGRectMake(0, 0, SpriteWidth, SpriteHeight), copy);
        CFRelease(copy);
	}
    CGImageRef imageMasked = CGBitmapContextCreateImage(context);
    CGContextRelease(context);
	
	UIGraphicsEndImageContext();
	
	UIImage *me = [[UIImage imageWithCGImage:imageMasked] retain];
	return me;
}


-(UIImage * )getSpriteAtRow:(float)row col:(float)col
{
	float x = [self SpriteWidth]  * col;
	float y = [self SpriteHeight] * row;
	
	return [self getSprite:x y:y];
}
@end
